package com.benshou.bcss.common.rest;

import com.benshou.bcss.common.asserts.BizAssert;
import com.benshou.bcss.common.trace.TraceIdContext;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.springframework.http.HttpStatus;

/**
 * @author <a href="mailto:liuzhenbang@benshou.com">Liu Zhenbang</a>
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {

    /**
     * 调用成功编码
     */
    public static final String SUCCESS_CODE = String.valueOf(HttpStatus.OK.value());

    /**
     * 调用错误编码
     */
    public static final String DEFAULT_ERROR_CODE = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());

    /**
     * 调用结果编码
     */
    @NonNull
    private String code = SUCCESS_CODE;

    /**
     * 调用结果消息
     */
    private String message = "success";

    /**
     * 调用结果数据
     */
    private T data;

    /**
     * 调用链路 Id
     */
    private String traceId = TraceIdContext.get();

    /**
     * 调用响应时间戳（毫秒级）
     */
    @NonNull
    private Long timestamp = System.currentTimeMillis();

    /**
     * 构建调用成功响应
     *
     * @return 响应实例
     * @param <T> 响应数据类型
     */
    public static <T> ApiResponse<T> success() {
        return new ApiResponse<>();
    }

    /**
     * 构建调用成功响应
     *
     * @param data 调用结果数据
     * @return 响应实例
     * @param <T> 响应数据类型
     */
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<T>().setData(data);
    }

    /**
     * 构建调用失败响应
     *
     * @param code 调用失败编码
     * @param message 调用失败消息
     * @return 响应实例
     * @param <T> 响应数据类型
     */
    public static <T> ApiResponse<T> fail(@NonNull String code, String message) {
        return new ApiResponse<T>()
                .setCode(code)
                .setMessage(message);
    }

    /**
     * 构建调用失败响应
     *
     * @param message 调用失败消息
     * @return 响应实例
     * @param <T> 响应数据类型
     */
    public static <T> ApiResponse<T> fail(String message) {
        return ApiResponse.fail(DEFAULT_ERROR_CODE, message);
    }

    /**
     * 构建调用失败响应
     *
     * @return 响应实例
     * @param <T> 响应数据类型
     */
    public static <T> ApiResponse<T> fail() {
        return fail("fail");
    }

    /**
     * @return 是否成功
     */
    public boolean isSuccess() {
        return SUCCESS_CODE.equals(this.code);
    }

    /**
     * 校验是否成功，如果成功，返回响应数据；否则抛出异常
     *
     * @return 响应数据
     */
    public T requireSuccessData() {
        BizAssert.isTrue(
                isSuccess(),
                "Response result is fail: code = " + this.code + ", message = " + this.message);

        return this.data;
    }
}
